//
//  CLThreadContainerViewController.m
//  Charles
//
//  Created by Charles on 2017/4/16.
//  Copyright © 2017年 charles. All rights reserved.
//

#import "CLThreadContainerViewController.h"
#import <pthread.h>
#import "AliveForeverThread.h"

@interface CLThreadContainerViewController (){
    UIImageView *imageView;
}

@property (strong,nonatomic) NSThread *thread;


@end

@implementation CLThreadContainerViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setUpView];
    [self setUpThread];
}

- (void)setUpView {

    UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 100, SCREEN_WIDTH - 40, 200)];
    textView.font = [UIFont systemFontOfSize:20.0f];
    textView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:textView];
    textView.text = @"UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 100, SCREEN_WIDTH - 40, 200)];\ntextView.backgroundColor = [UIColor lightGrayColor];\n[self.view addSubview:textView];UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 100, SCREEN_WIDTH - 40, 200)];\ntextView.backgroundColor = [UIColor lightGrayColor];\n[self.view addSubview:textView];UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 100, SCREEN_WIDTH - 40, 200)];\ntextView.backgroundColor = [UIColor lightGrayColor];\n[self.view addSubview:textView];UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 100, SCREEN_WIDTH - 40, 200)];\ntextView.backgroundColor = [UIColor lightGrayColor];\n[self.view addSubview:textView];";
    
    imageView = [[UIImageView alloc]initWithFrame:CGRectMake(20, CGRectGetMaxY(textView.frame) + 50, SCREEN_WIDTH - 40, 200)];
    imageView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:imageView];
    
}



- (void)setUpThread {
    if (self.type == CLThreadTypeGCD) {
        [self setUpGCD];
    }else if (self.type == CLThreadTypeRunLoop) {
        [self setUpRunLoop];
    }else if (self.type == CLThreadTypeNSOperation) {
        [self setUpOperation];
    }else if (self.type == CLThreadTypeThread) {
        [self setUpPthread];
    }
}
#pragma mark ---- GCD ----

- (void)setUpGCD {
    //同步任务，并发队列
    //    [self syncConcurrent];
    //异步任务，并发队列
    //    [self asyncConcurrent];
    //同步任务，串行队列
    //    [self syncSerial];
    //异步任务，串行队列
    //    [self asyncSerial];
    //同步任务，主队列(会Crash)
    /*
     互等卡住不可行(在主线程中调用)
     */
    //    [self syncMainQueue];
    /*
     在其他线程中调用
     不会开启新线程，执行完一个任务，再执行下一个任务
     */
    //    dispatch_queue_t queue = dispatch_queue_create("com.charles.otherthread", DISPATCH_QUEUE_CONCURRENT);
    //
    //    dispatch_async(queue, ^{
    //        [self syncMainQueue];
    //    });
    //异步任务，主队列
    //    [self asyncMainQueue];
    //GCD线程通讯
    //    [self threadCommunication];
    //GCD栅栏
    //    [self gcdBarrier];
    //GCD队列组
    //    [self gcdGroup];
    //GCD其他方法
    //[self gcdOther];
    //死锁举例
    [self deadLock];
//    [self gcdSemaphore];
//    [self gcdSemaphore2];
//    [self gcdSemaphore3];
    // 在子线程中，同步提交任务到主队列
//    [self subThreadSyncMainQueue];
//    [self delayTest];
}

- (void)delayTest {
    WEAKSELF(weakSelf);
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    /*
     测试 performSelector: withObject: afterDelay: 方法是否会执行
     */
    
    // 在异步自定义串行队列  不会调用delayMethod
    dispatch_async(queue, ^{
        [weakSelf performSelector:@selector(delayMethod) withObject:nil afterDelay:1];
    });

    // 在dispatch_after 自定义串行队列中执行  不会执行delayMethod2
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"current thread is %@",[NSThread currentThread]);
        [weakSelf performSelector:@selector(delayMethod2) withObject:nil afterDelay:1];
    });

    // dispatch_after 在主队列执行 会执行delayMethod3
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self performSelector:@selector(delayMethod3) withObject:nil afterDelay:1];
    });
}

- (void)delayMethod {
    NSLog(@"delay method invoke!");
}

- (void)delayMethod2 {
    NSLog(@"delay2 method invoke!");
}

- (void)delayMethod3{
    NSLog(@"delay3 method invoke!");
}

#pragma mark - 同步任务 并发队列

/**
 不会开启新线程，执行完一个任务，再执行下一个任务,所有任务都是在主线程中执行的.
 任务是添加到队列中马上执行.
 */

- (void)syncConcurrent {
    
    NSLog(@"----Charles thread begin----");
    //创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("com.charles.syncconcurrent", DISPATCH_QUEUE_CONCURRENT);
    //向队列中添加3个同步任务
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
}


#pragma mark - 异步任务 并发队列

/**
 可同时开启多线程，任务交替执行
 任务不是马上执行，而是将所有任务添加到队列之后才开始异步执行
 */

- (void)asyncConcurrent {
    
    NSLog(@"----Charles thread begin----");
    //创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("com.charles.asyncconcurrent", DISPATCH_QUEUE_CONCURRENT);
    //向队列中添加六个异步任务
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
}

#pragma mark - 同步任务 串行队列

/**
 不会开启新线程，在当前线程(main thread)执行任务。
 任务是串行的，执行完一个任务，再执行下一个任务
 任务是添加到队列中马上执行的
 */
- (void)syncSerial {
    
    NSLog(@"----Charles thread begin----");
    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.charles.syncserial", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
}

#pragma mark - 异步任务 串行队列

/**
 会开启一条新线程，但是因为任务是串行的，执行完一个任务，再执行下一个任务
 任务不是马上执行，而是将所有任务添加到队列之后才开始同步执行
 */
- (void)asyncSerial {
    
    NSLog(@"----Charles thread begin----");
    dispatch_queue_t queue = dispatch_queue_create("com.charles.asyncserial", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
}

#pragma mark - 同步任务 主队列(主线程的队列)

/**
 互等卡住不可行(在主线程中调用)
 
 这时候，我们惊奇的发现，在主线程中使用 主队列 + 同步执行，任务不再执行了，而且Charles thread end也没有打印。这是为什么呢？
 
 这是因为我们在主线程中执行这段代码。我们把任务放到了主队列中，也就是放到了主线程的队列中。而同步执行有个特点，就是对于任务是立马执行的。那么当我们把第一个任务放进主队列中，它就会立马执行。但是主线程现在正在处理syncMainQueue方法，所以任务需要等syncMainQueue执行完才能执行。而syncMainQueue执行到第一个任务的时候，又要等第一个任务执行完才能往下执行第二个和第三个任务。
 
 那么，现在的情况就是syncMainQueue方法和第一个任务都在等对方执行完毕。这样大家互相等待，所以就卡住了，所以我们的任务执行不了，而且Charles thread end也没有打印。
 */
- (void)syncMainQueue {
    
    NSLog(@"----Charles thread begin----");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
}

#pragma mark - 异步任务 主队列

/**
 只在主线程中执行任务，执行完一个任务，再执行下一个任务
 我们发现所有任务都在主线程中，虽然是异步执行，具备开启线程的能力，但因为是主队列，所以所有任务都在主线程中，并且一个接一个执行。
 另一方面可以看出，任务不是马上执行，而是将所有任务添加到队列之后才开始同步执行.
 */
- (void)asyncMainQueue {
    
    NSLog(@"----Charles thread begin----");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
    
}

#pragma mark - 子线程中同步提交任务到主队列中

- (void)subThreadSyncMainQueue {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"thread is %@",[NSThread currentThread]);
        [self subSyncMainQueue];
    });
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"thread is %@",[NSThread currentThread]);
    });
}

- (void)subSyncMainQueue {
    NSLog(@"first task!");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"block task!");
    });
    NSLog(@"last task!");
}

#pragma mark - GCD线程之间的通讯

/**
 在其他线程完成了耗时操作时，执行完了之后回到主线程执行主线程的相应操作
 */
- (void)threadCommunication {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (NSInteger i =0 ; i<4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"task_two %@",[NSThread currentThread]);
        });
    });
}

#pragma mark - GCD栅栏

/**
 我们有时需要异步执行两组操作，而且第一组操作执行完之后，才能开始执行第二组操作。这样我们就需要一个相当于栅栏一样的一个方法将两组异步执行的操作组给分割起来，当然这里的操作组里可以包含一个或多个任务。这就需要用到dispatch_barrier_async方法在两个操作组间形成栅栏
 */
- (void)gcdBarrier {
    
    NSLog(@"----Charles thread begin----");
    dispatch_queue_t queue = dispatch_queue_create("com.charles.asyncserial", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"task_barrier %@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_four %@",[NSThread currentThread]);
        }
    });
    NSLog(@"----Charles thread end----");
    
    
    dispatch_queue_t q = dispatch_queue_create("123", NULL);
    for (int i=0 ;i<10;i++) {
        dispatch_sync(q, ^{
            NSLog(@"%@=====%d",[NSThread currentThread],i);
        });
    }
    NSLog(@"123");
}

#pragma mark - GCD 队列组

/**
 有时候我们会有这样的需求：分别异步执行几个耗时操作，然后当几个耗时操作都执行完毕后再回到主线程执行操作。这时候我们可以用到GCD的队列组
 先把任务放到队列中，然后将队列放入队列组中
 */
- (void)gcdGroup {
    
    NSLog(@"----Charles thread begin----");
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_async(group, globalQueue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_one %@",[NSThread currentThread]);
        }
    });
    dispatch_group_async(group, globalQueue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_two %@",[NSThread currentThread]);
        }
    });
    dispatch_group_async(group, globalQueue, ^{
        for (NSInteger i = 0; i < 4; i++) {
            NSLog(@"task_three %@",[NSThread currentThread]);
        }
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"task_notify %@",[NSThread currentThread]);
    });
    NSLog(@"----Charles thread end----");
    
}

#pragma mark - CGD Semaphore CGD 线程同步

/**
 GCD线程同步,信号量
 */
- (void)gcdSemaphore {
    // 分别测试 value = 0 , 1 , 2, 3 的效果
    // 0 的时候没有任务执行  1 的时候相当于是串行队列
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(3); // 里面的参数设置的就是最大并发量
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 向并发队列中提交异步任务1
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"执行任务1");
        sleep(1);
        NSLog(@"任务1执行完成");
        dispatch_semaphore_signal(semaphore);
    });
    
    // 向并发队列中提交异步任务2
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"执行任务2");
        sleep(1);
        NSLog(@"任务2执行完成");
        dispatch_semaphore_signal(semaphore);
    });
    
    // 向并发队列中提交异步任务3
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"执行任务3");
        sleep(1);
        NSLog(@"任务3执行完成");
        dispatch_semaphore_signal(semaphore);
    });
}

- (void)gcdSemaphore2{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"执行任务1");
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"执行任务2");
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
   
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0 ), ^{
        NSLog(@"执行任务3");
        dispatch_semaphore_signal(semaphore);
    });
}

- (void)gcdSemaphore3{
//    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    for (NSInteger i = 0; i<10; i++) {
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"执行任务 %d",(int)i);
//            dispatch_semaphore_signal(semaphore);
        });
//        dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC));
    }
    /*
    NSLog(@"执行任务1");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"执行任务2");
    });
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"执行任务3");
    });
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"执行任务4");
    });
    NSLog(@"执行任务5");
     */
}

#pragma mark - GCD 其他方法

/**
 GCD 其他方法 执行一次和延时执行
 */
- (void)gcdOther {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"等待两秒执行!!");
    });
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"仅执行一次！！");
    });
    
    dispatch_queue_t queue = dispatch_queue_create("com.charles.apply", DISPATCH_QUEUE_CONCURRENT);
    dispatch_apply(6, queue, ^(size_t index) {
        NSLog(@"%zd------%@",index, [NSThread currentThread]);
    });
}

#pragma mark - 死锁

/**
 上面的同步任务+主队列 是死锁的一种；
 这个方法举例的是另一种死锁情况
 */
- (void)deadLock {
    
    //[self deadLockOne];
//    [self deadLockTwo];
    [self deadLockThree];
}

/**
 a.任务2 和 任务3 谁先加入 主线程的？
 ==> 因为 任务3 本身是在主线程里面的，任务2通过dispatch_get_main_queue()，添加到主线程的，所以就是3在前，任务2在后
 b.主线程是串行的，也就是先执行3，后执行任务2
 c.但是dispatch_sync，就会让进入等待状态，也就是任务3无法现在执行，只有等着任务2执行完后，才执行，
 步骤b,c 就相互等待，进入死锁了。
 */
- (void)deadLockOne {
    NSLog(@"1");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}

/**
 任务5，不在dispatch_queue_create里面，前面是dispatch_async，可能5先执行，也可能任务2先执行。
 现在4已经在dispatch_queue_create里面了，但是前面又有dispatch_sync，
 等着3，3也需要加入dispatch_queue_create，3在4后面，和第一题一样，相互等待，死锁。
 */
- (void)deadLockTwo {
    
    dispatch_queue_t queue = dispatch_queue_create("com.charles.deadlock", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); // 任务1
    dispatch_async(queue,^{
        NSLog(@"2");// 任务2
        dispatch_sync(queue, ^{
            NSLog(@"3"); // 任务3
        });
        NSLog(@"4"); // 任务4
    });
    NSLog(@"5"); // 任务5
}

- (void)deadLockThree {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1"); // 任务1
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2"); // 任务2
        });
        NSLog(@"3"); // 任务3
    });
    NSLog(@"4"); // 任务4
    //while (1) {}
    //NSLog(@"5"); // 任务5

}

#pragma mark ---- RunLoop ----

- (void)setUpRunLoop {
    //Timer 拖动textview timer 停止
    //[self dragTimerStop];
    //Timer 拖动textview timer 继续运行
    //[self dragTimerNotStop];
    //[self runLoopObserver];
    [self unDeadThread];
}

/**
 拖动scrollview timer停止运行
 */
- (void)dragTimerStop {
    /*
    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    上面这段代码等价于下面这段代码
     */
    NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
}

/**
 拖动scrollview timer继续运行
 */
-(void)dragTimerNotStop {
    NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)timerRun {
    NSLog(@"+++ timer +++");
}

/**
 观察者
 */
- (void)runLoopObserver {
    //创建观察者
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        NSLog(@"监听到RunLoop发生改变 --- %zd",activity);
    });
    //添加观察者到当前RunLoop中
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
    //释放observer，最后添加完需要释放掉
    CFRelease(observer);
}

/**
 后台常驻线程
 */
- (void)unDeadThread {
    self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(aliveThread) object:nil];
    [self.thread start];
}

- (void)aliveThread {
    
    NSLog(@"aliveThread");
    //添加下面两句代码，开启RunLoop，之后thread就变成了常驻线程，可以随时添加任务，并交于RunLoop处理。
    [[NSRunLoop currentRunLoop]addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop]run];
    //测试是否开启了RunLoop，如果开启了RunLoop,则来不到这里，因为RunLoop开启了循环。
    NSLog(@"未开启RunLoop");
}

- (void)threadAlive {
    NSLog(@"++++threadAlive");
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"timg.jpg"] afterDelay:4 inModes:@[NSDefaultRunLoopMode]];
    
    NSThread *aliveThread = [AliveForeverThread threadForDispatch];
    
    [self performSelector:@selector(threadAlive) onThread:aliveThread withObject:nil waitUntilDone:NO];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [AliveForeverThread stopThread];
    });
}

#pragma mark - ----Operation----


/**
 有三种方式来封装任务:
 使用子类NSInvocationOperation
 使用子类NSBlockOperation
 定义继承自NSOperation的子类，通过实现内部相应的方法来封装任务
 */
- (void)setUpOperation {
    /*
     在没有使用NSOperationQueue、单独使用NSInvocationOperation的情况下，
     NSInvocationOperation在主线程执行操作，并没有开启新线程。
     */
    //[self invocationOperationTest];
    
    //[self blockOperationTest];
    
    //[self operationTest];
    
    [self queueTest];
}

/**
 NSInvocationOperation
 */
- (void)invocationOperationTest {
    
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(invocationRun) object:nil];
    [operation start];
}

- (void)invocationRun {
    NSLog(@"invocationOperation thread is %@",[NSThread currentThread]);
}

- (void)blockOperationTest {
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"blockOperation thread is %@",[NSThread currentThread]);
    }];
    // 添加额外的任务(在子线程执行)
    [operation addExecutionBlock:^{
        NSLog(@"blockOperation thread is %@",[NSThread currentThread]);
    }];
    [operation start];
}

- (void)operationTest {
    CLOperation *operation = [[CLOperation alloc]init];
    [operation start];
}

- (void)queueTest {
    //[self addOperationToQueue];
    //[self addOperationWithBlockToQueue];
    [self operationQueue];
}

- (void)addOperationToQueue {
    // 1.创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 2. 创建操作
    // 创建NSInvocationOperation
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationRun) object:nil];
    // 创建NSBlockOperation
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    }];
    
    CLOperation * op3 = [[CLOperation alloc]init];
    
    // 3. 添加操作到队列中：addOperation: 任务自动执行
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
}

- (void)addOperationWithBlockToQueue {
    // 1. 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 2. 添加操作到队列中：addOperationWithBlock:
    [queue addOperationWithBlock:^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"-----%@", [NSThread currentThread]);
        }
    }];
}

- (void)operationQueue {
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 设置最大并发操作数
    //    queue.maxConcurrentOperationCount = 2;
    queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
    
    // 添加操作
    [queue addOperationWithBlock:^{
        NSLog(@"1-----%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:0.01];
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"2-----%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:0.01];
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"3-----%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:0.01];
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"4-----%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:0.01];
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"5-----%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:0.01];
    }];
    
    [queue addOperationWithBlock:^{
        NSLog(@"6-----%@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:0.01];
    }];
}

- (void)addDependency {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1-----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2-----%@", [NSThread  currentThread]);
    }];
    
    [op2 addDependency:op1];    // 让op2 依赖于 op1，则先执行op1，在执行op2
    
    [queue addOperation:op1];
    [queue addOperation:op2];
}
/*
 一些其他的方法：
 - (void)cancel; NSOperation提供的方法，可取消单个操作
 - (void)cancelAllOperations; NSOperationQueue提供的方法，可以取消队列的所有操作
 - (void)setSuspended:(BOOL)b; 可设置任务的暂停和恢复，YES代表暂停队列，NO代表恢复队列
 - (BOOL)isSuspended; 判断暂停状态
 
 注意：
 “这里的暂停和取消并不代表可以将当前的操作立即取消，而是当当前的操作执行完毕之后不再执行新的操作。
 
 暂停和取消的区别就在于：暂停操作之后还可以恢复操作，继续向下执行；而取消操作之后，
 所有的操作就清空了，无法再接着执行剩下的操作。
 */


#pragma mark - ----pthead & NSThread----

- (void)setUpPthread {
    [self pThreadTest];
}

- (void)pThreadTest {
    // 创建线程定义一个pthread_t类型变量
    pthread_t pthread;
    // 开启线程执行任务
    pthread_create(&pthread, NULL, &pthreadRun, NULL);
}

void * pthreadRun(void *param) {
    NSLog(@"%@", [NSThread currentThread]);
    return NULL;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

@implementation CLOperation

- (void)main {
    for (NSInteger i = 0; i < 2; i++) {
        NSLog(@"clOperation thread is %@",[NSThread currentThread]);
    }
}

@end
